#include "Partida.h"
#include "Jugador.h"
#include "Cerdito.h"

using namespace TP::Juego;
using namespace TP::Juego::Arena::Utilidades;

Partida::Partida() {
	this->_jugadorAdm = NULL;
	this->_arenaJuego = NULL;
}

Partida::Partida(const string& pNombre, Escenario* pEscenario,
		Jugador* pJugador) {
	if (pJugador) {
		Jugador* aux = new Jugador();
		aux->deElementoXML(pJugador->aElementoXML());
		this->_jugadorAdm = aux;
	}
	this->_jugadores.push_back(pJugador);
	this->_nombre = pNombre;
	this->_arenaJuego = pEscenario;

	// Se configura al jugador como propietario de un cerdito de la arena de
	// juego.
	Cerdito* avatar = (Cerdito*)pEscenario->getCerditoAvatar();
	if (avatar)
		avatar->setPropietario(pJugador);
}

Partida::~Partida() {
	//@todo: se debe liberar los recursos que consume la partida.
}

Escenario* Partida::ArenaJuego() {
	return this->_arenaJuego;
}

string Partida::aXML() {
	TiXmlDocument* doc = new TiXmlDocument();
	TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", "");
	doc->LinkEndChild(decl);

	doc->LinkEndChild(this->aElementoXML());

	TiXmlPrinter printer;
	doc->Accept(&printer);
	return printer.CStr();
}

string Partida::aXML(const string& pPath) {
	TiXmlDocument* doc = new TiXmlDocument(pPath.c_str());
	TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", "");
	doc->LinkEndChild(decl);

	doc->LinkEndChild(this->aElementoXML());

	TiXmlPrinter printer;
	doc->Accept(&printer);
	return printer.CStr();
}

void Partida::parseXML(const string& pDescriptor) {
	TiXmlDocument doc;
	doc.Parse(pDescriptor.c_str(), 0, TIXML_ENCODING_UTF8);
	this->deElementoXML(doc.FirstChildElement());
}

TiXmlElement* Partida::aElementoXML() {
	TiXmlElement* elementPartida = new TiXmlElement("Partida");

	elementPartida->SetAttribute("nombre", this->_nombre.c_str());

	// Serializo la arena de juego.
	elementPartida->LinkEndChild(this->_arenaJuego->aElementoXML());

	// Serializo los jugadores.
	TiXmlElement* element = new TiXmlElement("Jugadores");

	for (int cur = 0; cur < this->_jugadores.size(); cur++)
		element->LinkEndChild(this->_jugadores[cur]->aElementoXML());

	elementPartida->LinkEndChild(element);

	// Serializo el jugador administrador de la partida.
	if (this->_jugadorAdm != NULL)
		elementPartida->LinkEndChild(this->_jugadorAdm->aElementoXML());
	else
		elementPartida->LinkEndChild(new TiXmlElement("NULL"));

	return elementPartida;
}

void Partida::deElementoXML(TiXmlElement* pElemento) {
	if (pElemento->ValueTStr() == "Partida") {
		this->_nombre = pElemento->Attribute("nombre");

		// Hidrato la arena de juego.
		this->_arenaJuego = new Escenario();
		this->_arenaJuego->deElementoXML(pElemento->FirstChildElement());

		// Hidrato los jugadores.

		TiXmlElement* elemento = pElemento->FirstChildElement(
				)->NextSiblingElement()->FirstChildElement();
		while (NULL != elemento) {
			Jugador* jugador = new Jugador();
			jugador->deElementoXML(elemento);
			this->_jugadores.push_back(jugador);

			elemento = elemento->NextSiblingElement();
		}

		// Hidrato el jugador administrador.
		this->_jugadorAdm = NULL;
		if ("NULL" != pElemento->FirstChildElement()->NextSiblingElement(
				)->NextSiblingElement()->ValueTStr()) {
			this->_jugadorAdm = new Jugador();
			this->_jugadorAdm->deElementoXML(pElemento->FirstChildElement(
					)->NextSiblingElement()->NextSiblingElement());
		}
	}
}

vector<Jugador*>& Partida::getJugadores() {
	return this->_jugadores;
}

Partida* Partida::crearDeXML(const string& pDescriptor) throw (Excepcion&) {
	TiXmlDocument doc;
	doc.Parse(pDescriptor.c_str(), 0, TIXML_ENCODING_UTF8);

	if (doc.FirstChildElement()->ValueTStr() != "Partida")
		throw Excepcion("El descriptor no corresponde a una clase Partida.");

	Partida* partida = new Partida();
	partida->deElementoXML(doc.FirstChildElement());
	return partida;
}

const string& Partida::getNombre() {
	return this->_nombre;
}

Utilidad* Partida::getCerditoPorJugador(Jugador* pJugador) {
	return (Utilidad*) this->_arenaJuego->getCerditoAvatarPorJugador(pJugador);
}

Jugador* Partida::getJugadorAdministrador() {
	return this->_jugadorAdm;
}

Jugador* Partida::addJugador(Jugador* pJugador) {
	if (pJugador)
		this->_jugadores.push_back(pJugador);

	return pJugador;
}